﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ОпределитьНастройки();
	
	Параметры.Свойство("ОбъектОтбора", ОсновнойОбъект);
	ИсходныйОбъект = ОсновнойОбъект;
	
	Если ЗначениеЗаполнено(ОсновнойОбъект) Тогда
		ОбновитьДеревоСтруктурыПодчиненности();
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура Обновить(Команда)
	
	ВывестиСтруктуруПодчиненности();
	
КонецПроцедуры

&НаКлиенте
Процедура ВывестиДляТекущего(Команда)
	
	ТекущийОбъект = Элементы.ТаблицаОтчета.ТекущаяОбласть.Расшифровка;
	
	Если Не ЗначениеЗаполнено(ТекущийОбъект) Тогда
		Возврат;
	КонецЕсли;
	
	ОсновнойОбъект = ТекущийОбъект;
	
	ВывестиСтруктуруПодчиненности();
	
КонецПроцедуры

&НаКлиенте
Процедура ИзменитьПометкуУдаления(Команда)
	
	ОчиститьСообщения();
	
	ВыбранныеЭлементы = ВыбранныеЭлементы();
	
	Если ВыбранныеЭлементы.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Статистика = СтатистикаПоВыбраннымЭлементам(ВыбранныеЭлементы);
	
	Сценарий = СценарийИзмененияПометкиУдаления(ВыбранныеЭлементы, Статистика);
	Сценарий.Вставить("ВыбранныеЭлементы", ВыбранныеЭлементы);
	
	Обработчик = Новый ОписаниеОповещения("ВыполнитьСценарийИзмененияПометкиУдаления", ЭтотОбъект, Сценарий);
	ПоказатьВопрос(Обработчик, Сценарий.Вопрос, РежимДиалогаВопрос.ДаНет);
	
КонецПроцедуры

&НаКлиенте
Процедура Провести(Команда)
	
	ИзменитьПроведениеДокументов(РежимЗаписиДокумента.Проведение);
	
КонецПроцедуры

&НаКлиенте
Процедура ОтменитьПроведение(Команда)
	
	ИзменитьПроведениеДокументов(РежимЗаписиДокумента.ОтменаПроведения);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

//////////////////////////////////////////////////////////////////////////////////////////////
// Процедуры вывода в табличный документ.

&НаСервере
Процедура ВывестиТабличныйДокумент()

	ТаблицаОтчета.Очистить();
	
	Макет = ПолучитьОбщийМакет("СтруктураПодчиненности");
	
	ВывестиРодительскиеЭлементыДерева(ДеревоРодительскиеОбъекты.ПолучитьЭлементы(), Макет);
	ВывестиТекущийОбъект(Макет);
	ВывестиПодчиненныеЭлементыДерева(ДеревоПодчиненныеОбъекты.ПолучитьЭлементы(), Макет);
	
КонецПроцедуры

// Параметры:
//  СтрокиДерева - ДанныеФормыКоллекцияЭлементовДерева
//  Макет - ТабличныйДокумент
//  УровниРекурсии - Число
//
&НаСервере
Процедура ВывестиРодительскиеЭлементыДерева(СтрокиДерева, Макет, УровниРекурсии = 1)
	
	Счетчик =  СтрокиДерева.Количество();
	Пока Счетчик > 0 Цикл
		
		ТекущаяСтрокаДерева = СтрокиДерева.Получить(Счетчик - 1);
		
		ПодчиненныеЭлементыСтрокиДерева = ТекущаяСтрокаДерева.ПолучитьЭлементы();
		ВывестиРодительскиеЭлементыДерева(ПодчиненныеЭлементыСтрокиДерева, Макет, УровниРекурсии + 1);
		
		Для Уровень = 1 По УровниРекурсии Цикл
			
			Если Уровень = УровниРекурсии Тогда
				
				Если СтрокиДерева.Индекс(ТекущаяСтрокаДерева) < (СтрокиДерева.Количество() - 1) Тогда
					Область = Макет.ПолучитьОбласть("КоннекторВерхПравоНиз");
				Иначе
					Область = Макет.ПолучитьОбласть("КоннекторПравоНиз");
				КонецЕсли;
				
			Иначе
				
				Если ВыводитьВертикальныйКоннектор(УровниРекурсии - Уровень + 1, ТекущаяСтрокаДерева, Ложь) Тогда
					Область = Макет.ПолучитьОбласть("КоннекторВерхНиз");
				Иначе
					Область = Макет.ПолучитьОбласть("Отступ");
				КонецЕсли;
				
			КонецЕсли;
			
			Если Уровень = 1 Тогда
				ТаблицаОтчета.Вывести(Область);
			Иначе
				ТаблицаОтчета.Присоединить(Область);
			КонецЕсли;
			
		КонецЦикла;
		
		ВывестиПредставлениеИКартинку(ТекущаяСтрокаДерева, Макет, Ложь, Ложь);		
		Счетчик = Счетчик - 1;
		
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Процедура ВывестиПредставлениеИКартинку(СтрокаДерева, Макет, ЭтоТекущийОбъект = Ложь, ЭтоПодчиненный = Неопределено)
	
	МетаданныеОбъекта = СтрокаДерева.Ссылка.Метаданные();
	ЭтоДокумент       = ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта);
	
	ЕстьРодителиСуммарно = ДеревоРодительскиеОбъекты.ПолучитьЭлементы().Количество() > 0;
	ЕстьПодчиненныеСуммарно = ДеревоПодчиненныеОбъекты.ПолучитьЭлементы().Количество() > 0;
	ЕстьПодчиненные = ТипЗнч(СтрокаДерева) = Тип("ДанныеФормыЭлементДерева")
		И СтрокаДерева.ПолучитьЭлементы().Количество() > 0;
	
	// Вывод картинки
	Если СтрокаДерева.Проведен Тогда
		Если ЭтоТекущийОбъект Тогда
			Если ЕстьПодчиненныеСуммарно И ЕстьРодителиСуммарно Тогда
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведенКоннекторВерхНиз");
			ИначеЕсли ЕстьПодчиненныеСуммарно Тогда
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведенКоннекторНиз");
			Иначе
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведенКоннекторВерх");
			КонецЕсли;
		ИначеЕсли ЭтоПодчиненный = Истина Тогда
			Если ЕстьПодчиненные Тогда
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведенКоннекторЛевоНиз");
			Иначе
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведен");
			КонецЕсли;
		Иначе
			Если ЕстьПодчиненные Тогда
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведенКоннекторЛевоВерх");
			Иначе
				ОбластьКартинка = Макет.ПолучитьОбласть("ДокументПроведен");
			КонецЕсли;
		КонецЕсли;
	ИначеЕсли СтрокаДерева.ПометкаУдаления Тогда
		Если ЭтоТекущийОбъект Тогда
			Если ЕстьПодчиненныеСуммарно И ЕстьРодителиСуммарно  Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдалениеКоннекторВерхНиз", "СправочникПВХПомеченНаУдалениеКоннекторВерхНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			ИначеЕсли ЕстьПодчиненныеСуммарно Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдалениеКоннекторНиз", "СправочникПВХПомеченНаУдалениеКоннекторНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдалениеКоннекторВерх", "СправочникПВХПомеченНаУдалениеКоннекторВерх");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		ИначеЕсли ЭтоПодчиненный = Истина Тогда
			Если ЕстьПодчиненные Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдалениеКоннекторЛевоНиз", "СправочникПВХПомеченНаУдалениеКоннекторЛевоНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдаление", "СправочникПВХПомеченНаУдалениеКоннекторЛево");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		Иначе
			Если ЕстьПодчиненные Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдалениеКоннекторЛевоВерх", "СправочникПВХПомеченНаУдалениеКоннекторЛевоВерх");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументПомеченНаУдаление", "СправочникПВХПомеченНаУдалениеКоннекторЛево");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		КонецЕсли;
	Иначе
		Если ЭтоТекущийОбъект Тогда
			Если ЕстьПодчиненныеСуммарно И ЕстьРодителиСуммарно Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписанКоннекторВерхНиз", "СправочникПВХКоннекторВерхНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			ИначеЕсли ЕстьПодчиненныеСуммарно Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписанКоннекторНиз", "СправочникПВХКоннекторНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписанКоннекторВерх", "СправочникПВХКоннекторВерх");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		ИначеЕсли ЭтоПодчиненный = Истина Тогда
			Если ЕстьПодчиненные Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписанКоннекторЛевоНиз", "СправочникПВХКоннекторЛевоНиз");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписан", "СправочникПВХКоннекторЛево");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		Иначе
			Если ЕстьПодчиненные Тогда
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписанКоннекторЛевоВерх", "СправочникПВХКоннекторЛевоВерх");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			Иначе
				ИмяОбласти = ?(ЭтоДокумент, "ДокументЗаписан", "СправочникПВХКоннекторЛево");
				ОбластьКартинка = Макет.ПолучитьОбласть(ИмяОбласти);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Если ЭтоТекущийОбъект Тогда
		ТаблицаОтчета.Вывести(ОбластьКартинка) 
	Иначе
		ТаблицаОтчета.Присоединить(ОбластьКартинка);
	КонецЕсли;
	
	// Вывод объекта
	ОбластьОбъект = Макет.ПолучитьОбласть(?(ЭтоТекущийОбъект, "ТекущийОбъект", "Объект"));
	ОбластьОбъект.Параметры.ПредставлениеОбъекта = СтрокаДерева.Представление;
	ОбластьОбъект.Параметры.Объект = СтрокаДерева.Ссылка;
	ТаблицаОтчета.Присоединить(ОбластьОбъект);
	
КонецПроцедуры

// Определяет необходимость вывода вертикального коннектора в табличный документ.
//
// Параметры:
//  УровеньВверх  - Число - на каком количестве уровней выше находится 
//                 родитель от которого будет рисоваться вертикальный коннектор.
//  СтрокаДерева  - ДанныеФормыЭлементДерева - исходная строка дерева значений
//                  от которой ведется отсчет.
// Возвращаемое значение:
//   Булево   - необходимость вывода в области вертикального коннектора.
//
&НаСервере
Функция ВыводитьВертикальныйКоннектор(УровеньВверх, СтрокаДерева, ИщемСредиПодчиненных = Истина)
	
	ТекущаяСтрока = СтрокаДерева;
	
	Для инд = 1 По УровеньВверх Цикл
		
		ТекущаяСтрока = ТекущаяСтрока.ПолучитьРодителя();
		Если инд = УровеньВверх Тогда
			ИскомыйРодитель = ТекущаяСтрока;
		ИначеЕсли инд = (УровеньВверх-1) Тогда
			ИскомаяСтрока = ТекущаяСтрока;
		КонецЕсли;
		
	КонецЦикла;
	
	Если ИскомыйРодитель = Неопределено Тогда
		Если ИщемСредиПодчиненных Тогда
			ПодчиненныеЭлементыРодителя =  ДеревоПодчиненныеОбъекты.ПолучитьЭлементы(); 
		Иначе
			ПодчиненныеЭлементыРодителя =  ДеревоРодительскиеОбъекты.ПолучитьЭлементы();
		КонецЕсли;
	Иначе
		ПодчиненныеЭлементыРодителя =  ИскомыйРодитель.ПолучитьЭлементы(); 
	КонецЕсли;
	
	Возврат ПодчиненныеЭлементыРодителя.Индекс(ИскомаяСтрока) < (ПодчиненныеЭлементыРодителя.Количество()-1);
	
КонецФункции

// Выводит в табличный документ строку с документом, для которого формируется структура подчиненности.
//
// Параметры:
//  Макет - ТабличныйДокумент
//
&НаСервере
Процедура ВывестиТекущийОбъект(Макет)
	
	Выборка = ЗапросПоРеквизитамОбъектов(ОсновнойОбъект).Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		
		ПереопределяемоеПредставление = ПредставлениеОбъектаДляВывода(Выборка);
		Если ПереопределяемоеПредставление <> Неопределено Тогда
			СтруктураРеквизитов = ОбщегоНазначения.СтрокаТаблицыЗначенийВСтруктуру(Выборка.Владелец().Выгрузить()[0]);
			СтруктураРеквизитов.Представление = ПереопределяемоеПредставление;
			ВывестиПредставлениеИКартинку(СтруктураРеквизитов, Макет, Истина);
		Иначе
			СтруктураРеквизитов = ОбщегоНазначения.СтрокаТаблицыЗначенийВСтруктуру(Выборка.Владелец().Выгрузить()[0]);
			СтруктураРеквизитов.Представление = ПредставлениеОбъектаДляВыводаВОтчет(Выборка);
			ВывестиПредставлениеИКартинку(СтруктураРеквизитов, Макет, Истина);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//  Выборка - ВыборкаИзРезультатаЗапроса
//          - ДанныеФормыЭлементДерева - набор данных на основании которого формируется представление.
//
// Возвращаемое значение:
//   Строка - сформированное представление.
//
&НаСервере
Функция ПредставлениеОбъектаДляВыводаВОтчет(Выборка)
	
	ПредставлениеОбъекта = Выборка.Представление;
	МетаданныеОбъекта = Выборка.Ссылка.Метаданные();
	
	Если ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта) Тогда
		Если (Выборка.СуммаДокумента <> 0) И (Выборка.СуммаДокумента <> NULL) Тогда
			ПредставлениеОбъекта = ПредставлениеОбъекта
				+ " " + НСтр("ru = 'на сумму'")
				+ " " + Выборка.СуммаДокумента
				+ " " + Выборка.Валюта;
		КонецЕсли;
	Иначе
		ПредставлениеОбъекта = ПредставлениеОбъекта + " (" + ОбщегоНазначения.ПредставлениеОбъекта(МетаданныеОбъекта) + ")";
	КонецЕсли;
	
	Возврат ПредставлениеОбъекта;
	
КонецФункции

// Параметры:
//  СтрокиДерева - ДанныеФормыКоллекцияЭлементовДерева
//  Макет - ТабличныйДокумент
//  УровниРекурсии - Число
//
&НаСервере
Процедура ВывестиПодчиненныеЭлементыДерева(СтрокиДерева, Макет, УровниРекурсии = 1)

	Для каждого СтрокаДерева Из СтрокиДерева Цикл
		
		ЭтоИсходныйОбъект = (СтрокаДерева.Ссылка = ИсходныйОбъект);
		ПодчиненныеЭлементыДерева = СтрокаДерева.ПолучитьЭлементы();
		
		// Вывод коннекторов
		Для Уровень = 1 По УровниРекурсии Цикл
			
			Если УровниРекурсии > Уровень Тогда
				
				Если ВыводитьВертикальныйКоннектор(УровниРекурсии - Уровень + 1,СтрокаДерева) Тогда
					Область = Макет.ПолучитьОбласть("КоннекторВерхНиз");
				Иначе
					Область = Макет.ПолучитьОбласть("Отступ");
				КонецЕсли;
				
			Иначе 
				
				Если СтрокиДерева.Количество() > 1 И (СтрокиДерева.Индекс(СтрокаДерева) <> (СтрокиДерева.Количество() - 1)) Тогда
					Область = Макет.ПолучитьОбласть("КоннекторВерхПравоНиз");
				Иначе
					Область = Макет.ПолучитьОбласть("КоннекторВерхПраво");
				КонецЕсли;
				
			КонецЕсли;
			
			Область.Параметры.Документ = ?(ЭтоИсходныйОбъект, Неопределено, СтрокаДерева.Ссылка);
			
			Если Уровень = 1 Тогда
				ТаблицаОтчета.Вывести(Область);
			Иначе
				ТаблицаОтчета.Присоединить(Область);
			КонецЕсли;
			
		КонецЦикла;
		
		ВывестиПредставлениеИКартинку(СтрокаДерева, Макет, Ложь, Истина);		
		ВывестиПодчиненныеЭлементыДерева(ПодчиненныеЭлементыДерева, Макет, УровниРекурсии + 1);
		
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ВывестиСтруктуруПодчиненности()

	ОбновитьДеревоСтруктурыПодчиненности();

КонецПроцедуры

//////////////////////////////////////////////////////////////////////////////////////////////
// Процедуры построения дерева подчиненности документов.

&НаСервере
Процедура ОбновитьДеревоСтруктурыПодчиненности()

	Если Не ОсновнойДокументДоступен() Тогда
		
		ТекстСообщения = НСтр("ru = 'Документ, для которого сформирован отчет о структуре подчиненности, стал недоступен.'");
		ОбщегоНазначения.СообщитьПользователю(ТекстСообщения);
		Возврат;
		
	КонецЕсли;
	
	Заголовок = Метаданные.ОбщиеФормы.СвязанныеДокументы.Представление()
		+ ": " + ОбщегоНазначения.ПредметСтрокой(ОсновнойОбъект);
	
	СформироватьДеревьяДокументов();
	ВывестиТабличныйДокумент();
	
КонецПроцедуры

&НаСервере
Процедура СформироватьДеревьяДокументов()

	ДеревоРодительскиеОбъекты.ПолучитьЭлементы().Очистить();
	ДеревоПодчиненныеОбъекты.ПолучитьЭлементы().Очистить();
	
	ВыведенныеОбъекты = Новый Соответствие;
	
	ВывестиРодительскиеОбъекты(ОсновнойОбъект, ДеревоРодительскиеОбъекты, ВыведенныеОбъекты);
	ВывестиПодчиненныеОбъекты(ОсновнойОбъект, ДеревоПодчиненныеОбъекты, ВыведенныеОбъекты);
	
КонецПроцедуры

&НаСервере
Функция ОсновнойДокументДоступен()

	Запрос = Новый Запрос(
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	1
	|ИЗ
	|	&ИмяТаблицы КАК Таб
	|ГДЕ
	|	Таб.Ссылка = &ТекущийОбъект
	|");
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицы", ОсновнойОбъект.Метаданные().ПолноеИмя()); 
	Запрос.УстановитьПараметр("ТекущийОбъект", ОсновнойОбъект);
	Возврат Не Запрос.Выполнить().Пустой();

КонецФункции

// Параметры:
//  СписокОбъектов - Массив
//                 - ДокументСсылка
//                 - СправочникСсылка
//                 - ПланВидовХарактеристикСсылка
//
// Возвращаемое значение:
//   Запрос
//
&НаСервере
Функция ЗапросПоРеквизитамОбъектов(СписокОбъектов)
	
	ОбъектыПоТипу = Новый Соответствие;
	Если ТипЗнч(СписокОбъектов) = Тип("Массив") Тогда
		Для каждого ТекущийОбъект Из СписокОбъектов Цикл
			Объекты = ОбъектыПоТипу[ТекущийОбъект.Метаданные()];
			Если Объекты = Неопределено Тогда
				Объекты = Новый Массив;
				ОбъектыПоТипу[ТекущийОбъект.Метаданные()] = Объекты;
			КонецЕсли;
			Объекты.Добавить(ТекущийОбъект);
		КонецЦикла; 
	Иначе
		ОбъектыПоТипу[СписокОбъектов.Метаданные()] = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СписокОбъектов);
	КонецЕсли;
	
	Запрос = Новый Запрос;
	ТекстыЗапросов = Новый Массив;
	
	Для каждого ТипОбъекта Из ОбъектыПоТипу Цикл

		ТекстЗапроса = 
			"ВЫБРАТЬ РАЗРЕШЕННЫЕ
			|	&Дата КАК Дата,
			|	Ссылка,
			|	&Проведен КАК Проведен,
			|	ПометкаУдаления,
			|	&Сумма КАК СуммаДокумента,
			|	&Валюта КАК Валюта,
			|	&Представление
			|ИЗ
			|	&ИмяТаблицы
			|ГДЕ
			|	Ссылка В (&Ссылка)
			|";
		
		МетаданныеОбъекта = ТипОбъекта.Ключ;
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", МетаданныеОбъекта.ПолноеИмя());
		Если ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта) Тогда
			ИмяРеквизитаСумма    = ИмяРеквизитаДокумента(МетаданныеОбъекта, "СуммаДокумента");
			ИмяРеквизитаВалюта   = ИмяРеквизитаДокумента(МетаданныеОбъекта, "Валюта");
			ИмяРеквизитаПроведен = "Проведен";
			ИмяРеквизитаДата     = "Дата";
		Иначе
			ИмяРеквизитаСумма    = Неопределено;
			ИмяРеквизитаВалюта   = Неопределено;
			ИмяРеквизитаПроведен = "Ложь";
			ИмяРеквизитаДата     = "Ложь";
		КонецЕсли;
		
		ЗаменитьТекстЗапроса(ТекстЗапроса, МетаданныеОбъекта, "&Дата", ИмяРеквизитаДата, Истина);
		ЗаменитьТекстЗапроса(ТекстЗапроса, МетаданныеОбъекта, "&Проведен", ИмяРеквизитаПроведен, Истина);
		ЗаменитьТекстЗапроса(ТекстЗапроса, МетаданныеОбъекта, "&Сумма", ИмяРеквизитаСумма);
		ЗаменитьТекстЗапроса(ТекстЗапроса, МетаданныеОбъекта, "&Валюта", ИмяРеквизитаВалюта);
		
		ДопРеквизиты = РеквизитыДляПредставления(МетаданныеОбъекта.ПолноеИмя(), МетаданныеОбъекта.Имя);
		ТекстПредставление = "Представление КАК Представление"; // @query-part
		Для Индекс = 1 По 3 Цикл
			ТекстПредставление = ТекстПредставление + ",
				|	" + ?(ДопРеквизиты.Количество() >= Индекс, ДопРеквизиты[Индекс - 1], "NULL") 
				+ " КАК ДополнительныйРеквизит" + Индекс; // @query-part
		КонецЦикла;
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Представление", ТекстПредставление);
		
		ИмяПараметра = "Ссылка" + СтрЗаменить(МетаданныеОбъекта.ПолноеИмя(), ".", "_");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылка", "&" + ИмяПараметра);
		Запрос.УстановитьПараметр(ИмяПараметра, ТипОбъекта.Значение);
		
		Если ТекстыЗапросов.Количество() > 0 Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2
		КонецЕсли;

		ТекстыЗапросов.Добавить(ТекстЗапроса);
		
	КонецЦикла;
	
	Запрос.Текст = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); // @query-part
	Возврат Запрос; 
	
КонецФункции

&НаСервере
Процедура ВывестиРодительскиеОбъекты(ТекущийОбъект, ДеревоРодитель, ВыведенныеОбъекты,
	СлужебныеОбъекты = Неопределено, ИндексСвязейОбъектов = Неопределено)
	
	МетаданныеОбъекта = ТекущийОбъект.Метаданные();
	СписокРеквизитов  = Новый Массив;
	
	Если СлужебныеОбъекты = Неопределено Тогда 
		СлужебныеОбъекты = Новый Соответствие;
	КонецЕсли;
	
	Если ИндексСвязейОбъектов = Неопределено Тогда 
		ИндексСвязейОбъектов = Новый Соответствие;
	КонецЕсли;
	
	Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
		
		Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Состав.Содержит(Реквизит) Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого ТекущийТип Из Реквизит.Тип.Типы() Цикл
			
			МетаданныеРеквизита = МетаданныеТипаРеквизита(ТекущийТип);
			Если МетаданныеРеквизита.Метаданные = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ЗначениеРеквизита = ТекущийОбъект[Реквизит.Имя];
			Если ЗначениеЗаполнено(ЗначениеРеквизита)
				И ТипЗнч(ЗначениеРеквизита) = ТекущийТип
				И ЗначениеРеквизита <> ТекущийОбъект
				И СписокРеквизитов.Найти(ЗначениеРеквизита) = Неопределено Тогда
				
				СписокРеквизитов.Добавить(ЗначениеРеквизита);
			КонецЕсли;
		КонецЦикла;
		
	КонецЦикла;
	
	Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
		
		ИменаРеквизитов = "";
		СодержимоеТЧ = ТекущийОбъект[ТабличнаяЧасть.Имя].Выгрузить(); // ТаблицаЗначений
		Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл

			Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Состав.Содержит(Реквизит) Тогда
				Продолжить;
			КонецЕсли;
				
			Для Каждого ТекущийТип Из Реквизит.Тип.Типы() Цикл
				МетаданныеРеквизита = МетаданныеТипаРеквизита(ТекущийТип);
				Если МетаданныеРеквизита.Метаданные = Неопределено Тогда
					Продолжить;
				КонецЕсли;
	
				ИменаРеквизитов = ИменаРеквизитов + ?(ИменаРеквизитов = "", "", ", ") + Реквизит.Имя;
				Прервать;
			КонецЦикла;
			
		КонецЦикла;
		
		СодержимоеТЧ.Свернуть(ИменаРеквизитов);
		Для Каждого КолонкаТЧ Из СодержимоеТЧ.Колонки Цикл
			
			Для Каждого СтрокаТЧ Из СодержимоеТЧ Цикл
			
				ЗначениеРеквизита = СтрокаТЧ[КолонкаТЧ.Имя];
				МетаданныеЗначения = МетаданныеТипаРеквизита(ТипЗнч(ЗначениеРеквизита));
				Если МетаданныеЗначения.Метаданные = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				Если ЗначениеРеквизита = ТекущийОбъект
					Или СписокРеквизитов.Найти(ЗначениеРеквизита) <> Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				СписокРеквизитов.Добавить(ЗначениеРеквизита);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Если СписокРеквизитов.Количество() > 0 Тогда
		ВыводимыеОбъекты = ЗапросПоРеквизитамОбъектов(СписокРеквизитов).Выполнить().Выгрузить();
		ВыводимыеОбъекты.Сортировать("Дата");
		Для каждого ВыводимыйОбъект Из ВыводимыеОбъекты Цикл 
			
			Если ИндексСвязейОбъектов[ТекущийОбъект] = ВыводимыйОбъект.Ссылка Тогда 
				Продолжить;
			КонецЕсли;
			
			ИндексСвязейОбъектов[ТекущийОбъект] = ВыводимыйОбъект.Ссылка;
			
			НоваяСтрока = ДобавитьСтрокуВДерево(ДеревоРодитель, ВыводимыйОбъект, ВыведенныеОбъекты);			
			Если НоваяСтрока <> Неопределено
				И Не ДобавляемыйОбъектИмеетсяСредиРодителей(ДеревоРодитель, ВыводимыйОбъект.Ссылка) Тогда
				
				// @skip-check query-in-loop - Рекурсивный алгоритм обработки дерева.
				ВывестиРодительскиеОбъекты(ВыводимыйОбъект.Ссылка, НоваяСтрока, ВыведенныеОбъекты,
					СлужебныеОбъекты, ИндексСвязейОбъектов);
				
			ИначеЕсли СлужебныеОбъекты[ВыводимыйОбъект.Ссылка] = Неопределено Тогда 
				
				СлужебныеОбъекты[ВыводимыйОбъект.Ссылка] = Истина;
				// @skip-check query-in-loop - Рекурсивный алгоритм обработки дерева.
				ВывестиРодительскиеОбъекты(ВыводимыйОбъект.Ссылка, ДеревоРодитель, ВыведенныеОбъекты,
					СлужебныеОбъекты, ИндексСвязейОбъектов);
				
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//  ТипРеквизита - Тип
// 
// Возвращаемое значение:
//  Структура:
//   * Метаданные - ОбъектМетаданных
//   * ЭтоДокумент - Булево
//
&НаСервереБезКонтекста
Функция МетаданныеТипаРеквизита(ТипРеквизита)

	Результат = Новый Структура("Метаданные, ЭтоДокумент", Неопределено, Ложь); 
	
	МетаданныеРеквизита = Метаданные.НайтиПоТипу(ТипРеквизита);
	Если МетаданныеРеквизита = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(МетаданныеРеквизита) 
		Или Не ПравоДоступа("Просмотр", МетаданныеРеквизита) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Результат.ЭтоДокумент = Метаданные.Документы.Содержит(МетаданныеРеквизита);
	Если Не Результат.ЭтоДокумент
		И Не Метаданные.Справочники.Содержит(МетаданныеРеквизита)
		И Не Метаданные.ПланыВидовХарактеристик.Содержит(МетаданныеРеквизита) Тогда
		Возврат Результат;
	КонецЕсли;
	Результат.Метаданные = МетаданныеРеквизита;
	Возврат Результат;

КонецФункции

// Параметры:
//  СтрокаРодитель  - ДанныеФормыДерево
//                  - ДанныеФормыЭлементДерева
//  ИскомыйОбъект  - ЛюбаяСсылка
//
// Возвращаемое значение:
//   Булево
//
&НаСервере
Функция ДобавляемыйОбъектИмеетсяСредиРодителей(СтрокаРодитель, ИскомыйОбъект)
	
	Если ИскомыйОбъект = ОсновнойОбъект Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ТипЗнч(СтрокаРодитель) = Тип("ДанныеФормыДерево") Тогда
		Возврат Ложь; 
	КонецЕсли;
	
	ТекущийРодитель = СтрокаРодитель;
	Пока ТекущийРодитель <> Неопределено Цикл
		Если ТекущийРодитель.Ссылка = ИскомыйОбъект Тогда
			Возврат Истина;
		КонецЕсли;
		ТекущийРодитель = ТекущийРодитель.ПолучитьРодителя();
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

&НаСервере
Процедура ЗаменитьТекстЗапроса(ТекстЗапроса, МетаданныеОбъекта, ЧтоЗаменять, ИмяРеквизита, НеИскатьВРеквизитах = Ложь)

	ЕстьРеквизит = НеИскатьВРеквизитах Или МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено; 
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ЧтоЗаменять, ?(ЕстьРеквизит, ИмяРеквизита,  "NULL"));

КонецПроцедуры

// Возвращает ссылки на связанные объекты.
// 
// Возвращаемое значение:
//   ТаблицаЗначений:
//     * Ссылка - СправочникСсылка
//              - ДокументСсылка
//
&НаСервере
Функция ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора)

	ШаблонЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	ПредставлениеТаблицы.Ссылка КАК Ссылка
	|ИЗ
	|	ИмяТаблицы КАК ПредставлениеТаблицы
	|ГДЕ
	|	ПредставлениеТаблицы.ИмяРеквизита = &ЗначениеКритерияОтбора";

	ШаблонЗапросаОбъединения = "ВЫБРАТЬ
	|	ПредставлениеТаблицы.Ссылка КАК Ссылка
	|ИЗ
	|	ИмяТаблицы КАК ПредставлениеТаблицы
	|ГДЕ
	|	ПредставлениеТаблицы.ИмяРеквизита = &ЗначениеКритерияОтбора";

	ЧастиЗапроса = Новый Массив;
	ТекстЧастиЗапроса = "";

	Для Каждого ЭлементСостава Из Метаданные.КритерииОтбора.СвязанныеДокументы.Состав Цикл

		Если НЕ ЭлементСостава.Тип.СодержитТип(ТипЗнч(ЗначениеКритерияОтбора)) Тогда
			Продолжить;
		КонецЕсли;

		ПутьКДанным = ЭлементСостава.ПолноеИмя();
		
		Если СтрНайти(ПутьКДанным, "ТабличнаяЧасть") Тогда
			ОбъектМетаданных = ЭлементСостава.Родитель().Родитель();
		Иначе
			ОбъектМетаданных = ЭлементСостава.Родитель();
		КонецЕсли;
				
		Если НЕ ПравоДоступа("Чтение", ОбъектМетаданных) Тогда
			Продолжить;
		КонецЕсли;

		Точка = СтрНайти(ПутьКДанным, ".", НаправлениеПоиска.СКонца);
		ИмяРеквизита = Сред(ПутьКДанным, Точка + 1);

		ИмяТаблицы = ЭлементСостава.Родитель().ПолноеИмя();
		ИмяТаблицы = СтрЗаменить(ИмяТаблицы, "ТабличнаяЧасть.", "");

		Точка = СтрНайти(ИмяТаблицы, ".", НаправлениеПоиска.СКонца);
		ПредставлениеТаблицы = Сред(ИмяТаблицы, Точка + 1);

		ТекстЧастиЗапроса = ?(ТекстЧастиЗапроса = "", ШаблонЗапроса, ШаблонЗапросаОбъединения);
		ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ИмяТаблицы", ИмяТаблицы);
		ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ПредставлениеТаблицы", ПредставлениеТаблицы);
		ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ИмяРеквизита", ИмяРеквизита);

		ЧастиЗапроса.Добавить(ТекстЧастиЗапроса);

	КонецЦикла;

	Если ЧастиЗапроса.Количество() > 0 Тогда
		Запрос = Новый Запрос;
		Разделитель = Символы.ПС + "ОБЪЕДИНИТЬ" + Символы.ПС;
		Запрос.Текст = СтрСоединить(ЧастиЗапроса, Разделитель);
		Запрос.УстановитьПараметр("ЗначениеКритерияОтбора", ЗначениеКритерияОтбора);
		Возврат Запрос.Выполнить().Выгрузить();
	Иначе
		Возврат Новый ТаблицаЗначений;
	КонецЕсли;

КонецФункции

&НаСервере
Процедура ВывестиПодчиненныеОбъекты(ТекущийОбъект, ДеревоРодитель, ВыведенныеОбъекты,
	СлужебныеОбъекты = Неопределено, ИндексСвязейОбъектов = Неопределено)
	
	Таблица = ОбъектыПоКритериюОтбора(ТекущийОбъект);
	Если Таблица = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если СлужебныеОбъекты = Неопределено Тогда 
		СлужебныеОбъекты = Новый Соответствие;
	КонецЕсли;
	
	Если ИндексСвязейОбъектов = Неопределено Тогда 
		ИндексСвязейОбъектов = Новый Соответствие;
	КонецЕсли;
	
	СписокОбъектов = Новый Массив;
	Для Каждого СтрокаТаблицы Из Таблица Цикл

		ТекущаяСсылка = СтрокаТаблицы.Ссылка; // СправочникСсылка, ДокументСсылка		
		МетаданныеОбъекта = ТекущаяСсылка.Метаданные();
		Если Не ПравоДоступа("Просмотр", МетаданныеОбъекта) Тогда
			Продолжить;
		КонецЕсли;

		СписокОбъектов.Добавить(ТекущаяСсылка);
	КонецЦикла;
	
	Если СписокОбъектов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ВыводимыеОбъекты = ЗапросПоРеквизитамОбъектов(СписокОбъектов).Выполнить().Выгрузить();
	ВыводимыеОбъекты.Сортировать("Дата");

	Для каждого ВыводимыйОбъект Из ВыводимыеОбъекты Цикл
		
		Если ИндексСвязейОбъектов[ТекущийОбъект] = ВыводимыйОбъект.Ссылка Тогда 
			Продолжить;
		КонецЕсли;
		
		ИндексСвязейОбъектов[ТекущийОбъект] = ВыводимыйОбъект.Ссылка;
		
		НоваяСтрока = ДобавитьСтрокуВДерево(ДеревоРодитель, ВыводимыйОбъект, ВыведенныеОбъекты, Истина);		
		Если НоваяСтрока <> Неопределено
			И Не ДобавляемыйОбъектИмеетсяСредиРодителей(ДеревоРодитель, ВыводимыйОбъект.Ссылка) Тогда
			
			// @skip-check query-in-loop - Рекурсивный алгоритм обработки дерева.
			ВывестиПодчиненныеОбъекты(ВыводимыйОбъект.Ссылка, НоваяСтрока, ВыведенныеОбъекты,
				СлужебныеОбъекты, ИндексСвязейОбъектов);
			
		ИначеЕсли СлужебныеОбъекты[ВыводимыйОбъект.Ссылка] = Неопределено Тогда 
			
			СлужебныеОбъекты.Вставить(ВыводимыйОбъект.Ссылка, Истина);
			// @skip-check query-in-loop - Рекурсивный алгоритм обработки дерева.
			ВывестиПодчиненныеОбъекты(ВыводимыйОбъект.Ссылка, ДеревоРодитель, ВыведенныеОбъекты,
				СлужебныеОбъекты, ИндексСвязейОбъектов);
			
		КонецЕсли;
		
	КонецЦикла;

КонецПроцедуры

&НаСервере
Функция ДобавитьСтрокуВДерево(Родитель, Данные, ВыведенныеОбъекты, ЭтоПодчиненный = Ложь)
	
	УстановитьЧастотуВыводаОбъекта(Данные.Ссылка, ВыведенныеОбъекты, ЭтоПодчиненный);	
	Если Не ВыводитьТекущийОбъект(Родитель, Данные.Ссылка, ВыведенныеОбъекты, ЭтоПодчиненный) Тогда 
		Возврат Неопределено;
	КонецЕсли;
	
	НоваяСтрока = Родитель.ПолучитьЭлементы().Добавить();
	ОбщиеСвойства = "Ссылка, Представление, СуммаДокумента, Валюта, Проведен, ПометкаУдаления";
	ЗаполнитьЗначенияСвойств(НоваяСтрока, Данные, ОбщиеСвойства);
	
	ПереопределенноеПредставление = ПредставлениеОбъектаДляВывода(Данные);
	Если ПереопределенноеПредставление <> Неопределено Тогда
		НоваяСтрока.Представление = ПереопределенноеПредставление;
	Иначе
		НоваяСтрока.Представление = ПредставлениеОбъектаДляВыводаВОтчет(Данные);
	КонецЕсли;
	
	Возврат НоваяСтрока;
	
КонецФункции

&НаСервере
Функция ВыводитьТекущийОбъект(Родитель, ТекущийОбъект, ВыведенныеОбъекты, ЭтоПодчиненный, Отказ = Ложь)
	
	Выводился = ВыведенныеОбъекты[ТекущийОбъект];
	Если Выводился = Неопределено Тогда 
		Выводился = НовыеСвойстваЧастотыВыводаОбъекта();
	КонецЕсли;
	
	СвойстваОбъекта = НовыеСвойстваОбъекта();
	СвойстваОбъекта.ЭтоОсновной = (ТекущийОбъект = ОсновнойОбъект);
	СвойстваОбъекта.ЭтоПодчиненный = ЭтоПодчиненный;
	СвойстваОбъекта.Выводился = Выводился;
	
	Если СвойстваОбъекта.ЭтоОсновной
		Или ТекущийОбъектВыводилсяВВетке(Родитель, ТекущийОбъект) Тогда 
		
		Отказ = Истина;
	КонецЕсли;
	
	СтруктураПодчиненностиПереопределяемый.ПередВыводомСвязанногоОбъекта(ТекущийОбъект, СвойстваОбъекта, Отказ);
	
	Возврат Не Отказ;
	
КонецФункции

&НаСервере
Функция НовыеСвойстваОбъекта()
	
	СвойстваОбъекта = Новый Структура;
	СвойстваОбъекта.Вставить("ЭтоОсновной", Ложь);
	СвойстваОбъекта.Вставить("ЭтоСлужебный", Ложь);
	СвойстваОбъекта.Вставить("ЭтоПодчиненный", Ложь);
	СвойстваОбъекта.Вставить("Выводился", НовыеСвойстваЧастотыВыводаОбъекта());
	
	Возврат СвойстваОбъекта;
	
КонецФункции

&НаСервере
Функция ТекущийОбъектВыводилсяВВетке(Родитель, ТекущийОбъект, Выводился = Ложь)
	
	Если Родитель = Неопределено Тогда 
		Возврат Выводился;
	КонецЕсли;
	
	ЭтоСтрока = (ТипЗнч(Родитель) = Тип("ДанныеФормыЭлементДерева"));
	
	Если ЭтоСтрока И ТекущийОбъект = Родитель.Ссылка Тогда 
		Выводился = Истина;
	Иначе
		Строки = Родитель.ПолучитьЭлементы();
		
		Для Каждого Строка Из Строки Цикл 
			
			Если ТекущийОбъект = Строка.Ссылка Тогда 
				
				Выводился = Истина;
				Прервать;
				
			КонецЕсли;
			
		КонецЦикла;
		
		Если ЭтоСтрока И Не Выводился Тогда 
			ТекущийОбъектВыводилсяВВетке(Родитель.ПолучитьРодителя(), ТекущийОбъект, Выводился);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Выводился;
	
КонецФункции

&НаСервере
Процедура УстановитьЧастотуВыводаОбъекта(ТекущийОбъект, ВыведенныеОбъекты, ЭтоПодчиненный)
	
	Выводился = ВыведенныеОбъекты[ТекущийОбъект];
	Если Выводился = Неопределено Тогда 
		Выводился = НовыеСвойстваЧастотыВыводаОбъекта();
	КонецЕсли;
	
	Выводился.Итого = Выводился.Итого + 1;
	Если ЭтоПодчиненный Тогда 
		Выводился.ВПодчиненных = Выводился.ВПодчиненных + 1;
	КонецЕсли;
	
	ВыведенныеОбъекты.Вставить(ТекущийОбъект, Выводился);
	
КонецПроцедуры

&НаСервере
Функция НовыеСвойстваЧастотыВыводаОбъекта()
	
	СвойстваЧастотыВывода = Новый Структура;
	СвойстваЧастотыВывода.Вставить("Итого", 0);
	СвойстваЧастотыВывода.Вставить("ВПодчиненных", 0);	
	Возврат СвойстваЧастотыВывода;
	
КонецФункции

&НаСервере
Функция ИмяРеквизитаДокумента(Знач МетаданныеОбъекта, Знач ИмяРеквизита) 
	
	ИменаРеквизитов = Настройки.Реквизиты[МетаданныеОбъекта.ПолноеИмя()];
	Если ИменаРеквизитов <> Неопределено Тогда
		Результат = ИменаРеквизитов[ИмяРеквизита];
		Возврат ?(Результат <> Неопределено, Результат, ИмяРеквизита);
	КонецЕсли;	
	
	// Для обратной совместимости.
	ИмяРеквизитаДокумента = СтруктураПодчиненностиПереопределяемый.ИмяРеквизитаДокумента(МетаданныеОбъекта.Имя, ИмяРеквизита); // АПК:223
	Если ИмяРеквизита = "СуммаДокумента" Тогда
		Возврат ?(ИмяРеквизитаДокумента = Неопределено, "СуммаДокумента", ИмяРеквизитаДокумента);
	ИначеЕсли ИмяРеквизита = "Валюта" Тогда
		Возврат ?(ИмяРеквизитаДокумента = Неопределено, "Валюта", ИмяРеквизитаДокумента);
	КонецЕсли;
	
КонецФункции

&НаСервере
Процедура ОпределитьНастройки()
	
	НастройкиПодсистемы = Новый Структура;
	НастройкиПодсистемы.Вставить("Реквизиты", Новый Соответствие);
	НастройкиПодсистемы.Вставить("РеквизитыДляПредставления", Новый Соответствие);
	СтруктураПодчиненностиПереопределяемый.ПриОпределенииНастроек(НастройкиПодсистемы);
	
	Настройки = НастройкиПодсистемы;

КонецПроцедуры

&НаСервере
Функция РеквизитыДляПредставления(Знач ПолноеИмяОбъектаМетаданных, Знач ИмяОбъектаМетаданных)
	
	Результат = Настройки.РеквизитыДляПредставления[ПолноеИмяОбъектаМетаданных];
	Если Результат <> Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	// Для обратной совместимости.
	Возврат СтруктураПодчиненностиПереопределяемый.МассивРеквизитовОбъектаДляФормированияПредставления(ИмяОбъектаМетаданных); // АПК:223
	
КонецФункции

&НаСервере
Функция ПредставлениеОбъектаДляВывода(Данные) 
	
	Результат = "";
	СтандартнаяОбработка = Истина;	
	СтруктураПодчиненностиПереопределяемый.ПриПолученииПредставления(ТипЗнч(Данные.Ссылка), Данные, Результат, СтандартнаяОбработка);
	Если Не СтандартнаяОбработка Тогда
		Возврат Результат;
	КонецЕсли;
	
	// Для обратной совместимости.
	Возврат СтруктураПодчиненностиПереопределяемый.ПредставлениеОбъектаДляВыводаВОтчет(Данные); // АПК:223
	
КонецФункции

//////////////////////////////////////////////////////////////////////////////////////////////
// Процедуры изменения состояния объектов.

&НаКлиенте
Функция ВыбранныеЭлементы()
	
	ВыбранныеЭлементы = Новый Массив;
	
	ВыделенныеОбласти = Элементы.ТаблицаОтчета.ПолучитьВыделенныеОбласти();
	
	Для Каждого ВыделеннаяОбласть Из ВыделенныеОбласти Цикл 
		
		Если ТипЗнч(ВыделеннаяОбласть) <> Тип("ОбластьЯчеекТабличногоДокумента") Тогда
			Продолжить;
		КонецЕсли;
		
		Границы = ГраницыВыделеннойОбласти(ВыделеннаяОбласть);
		
		Для НомерКолонки = Границы.Лево По Границы.Право Цикл
			
			Для НомерСтроки = Границы.Верх По Границы.Низ Цикл
				
				Ячейка = ТаблицаОтчета.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
				
				Если ЗначениеЗаполнено(Ячейка.Расшифровка) Тогда 
					ВыбранныеЭлементы.Добавить(Ячейка.Расшифровка);
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат ВыбранныеЭлементы;
	
КонецФункции

&НаКлиенте
Функция ГраницыВыделеннойОбласти(ВыделеннаяОбласть)
	
	Границы = Новый Структура("Лево, Верх, Низ, Право");
	ЗаполнитьЗначенияСвойств(Границы, ВыделеннаяОбласть);
	
	Если Границы.Лево = 0 Тогда 
		Границы.Лево = 1;
	КонецЕсли;
	
	Если Границы.Верх = 0 Тогда 
		Границы.Верх = 1;
	КонецЕсли;
	
	Если Границы.Низ = 0 Тогда 
		Границы.Низ = 1;
	КонецЕсли;
	
	Если Границы.Право = 0 Тогда 
		Границы.Право = 1;
	КонецЕсли;
	
	Возврат Границы;
	
КонецФункции

// Изменение пометки удаления.

&НаСервереБезКонтекста
Функция СтатистикаПоВыбраннымЭлементам(ВыбранныеЭлементы)
	
	Статистика = Новый Структура;
	Статистика.Вставить("СПометкойНаУдаление", Новый Соответствие);
	Статистика.Вставить("БезПометкиНаУдаление", Новый Соответствие);
	
	СвойстваЭлементов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(ВыбранныеЭлементы, "ПометкаУдаления, Представление");
	
	Для Каждого Элемент Из ВыбранныеЭлементы Цикл 
		
		СвойстваЭлемента = СвойстваЭлементов[Элемент];
		
		Если СвойстваЭлемента.ПометкаУдаления Тогда 
			Статистика.СПометкойНаУдаление.Вставить(Элемент, СвойстваЭлемента.Представление);
		Иначе
			Статистика.БезПометкиНаУдаление.Вставить(Элемент, СвойстваЭлемента.Представление);
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Статистика;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Пояснение - Строка
//   * Ссылка - Строка
//   * Оповещение - Строка
//   * Вопрос - Строка
//   * Пометка - Булево
//
&НаКлиенте
Функция СценарийИзмененияПометкиУдаления(ВыбранныеЭлементы, СтатистикаПоВыбраннымЭлементам)
	
	Сценарий = Новый Структура;
	Сценарий.Вставить("Пометка", Ложь);
	Сценарий.Вставить("Вопрос", "");
	Сценарий.Вставить("Оповещение", "");
	Сценарий.Вставить("Ссылка", "");
	Сценарий.Вставить("Пояснение", "");
	
	КоличествоВыбранныхЭлементов = ВыбранныеЭлементы.Количество();
	КоличествоПомеченныхНаУдаление = СтатистикаПоВыбраннымЭлементам.СПометкойНаУдаление.Количество();
	
	Если КоличествоВыбранныхЭлементов = 1 Тогда 
		
		Элемент = ВыбранныеЭлементы[0];
		Сценарий.Ссылка = ПолучитьНавигационнуюСсылку(Элемент);
		
		Если КоличествоПомеченныхНаУдаление = 0 Тогда 
			
			ПредставлениеЭлемента = СтатистикаПоВыбраннымЭлементам.БезПометкиНаУдаление[Элемент];
			
			Сценарий.Пометка = Истина;
			Сценарий.Оповещение = НСтр("ru = 'Пометка удаления установлена'");
			Сценарий.Пояснение = ПредставлениеЭлемента;
			Сценарий.Вопрос = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Пометить ""%1"" на удаление?'"), ПредставлениеЭлемента);
			
		Иначе
			
			ПредставлениеЭлемента = СтатистикаПоВыбраннымЭлементам.СПометкойНаУдаление[Элемент];
			
			Сценарий.Оповещение = НСтр("ru = 'Пометка удаления снята'");
			Сценарий.Пояснение = ПредставлениеЭлемента;
			Сценарий.Вопрос = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Снять с ""%1"" пометку на удаление?'"), ПредставлениеЭлемента);
			
		КонецЕсли;
		
	Иначе
		
		Сценарий.Пояснение = Заголовок;
		
		Если КоличествоПомеченныхНаУдаление = 0 Тогда 
			
			Сценарий.Пометка = Истина;
			Сценарий.Вопрос = НСтр("ru = 'Пометить выделенные элементы на удаление?'");
			Сценарий.Оповещение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Пометка удаления установлена (%1)'"), КоличествоВыбранныхЭлементов);
		
		ИначеЕсли КоличествоПомеченныхНаУдаление = КоличествоВыбранныхЭлементов Тогда 
			
			Сценарий.Вопрос = НСтр("ru = 'Снять с выделенных элементов пометку на удаление?'");
			Сценарий.Оповещение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Пометка удаления снята (%1)'"), КоличествоВыбранныхЭлементов);
			
		Иначе
			
			// Если часть выбранных элементов помечена на удаление, то система должна обработать только их, сняв пометку.
			ВыбранныеЭлементы.Очистить();
			
			Для Каждого Элемент Из СтатистикаПоВыбраннымЭлементам.СПометкойНаУдаление Цикл 
				ВыбранныеЭлементы.Добавить(Элемент.Ключ);
			КонецЦикла;
			
			Сценарий = СценарийИзмененияПометкиУдаления(ВыбранныеЭлементы, СтатистикаПоВыбраннымЭлементам);
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Сценарий;
	
КонецФункции

// Параметры:
//  Ответ - КодВозвратаДиалога
//  Сценарий - см. СценарийИзмененияПометкиУдаления
//
&НаКлиенте
Процедура ВыполнитьСценарийИзмененияПометкиУдаления(Ответ, Сценарий) Экспорт 
	
	Если Ответ <> КодВозвратаДиалога.Да Тогда 
		Возврат;
	КонецЕсли;
	
	Ошибки = ИзменитьПометкуУдаленияЭлементов(Сценарий.ВыбранныеЭлементы, Сценарий.Пометка);
	Если Ошибки.Количество() > 0 Тогда 
		ПредупредитьОбОшибкеПриИзмененииЭлементов(Ошибки, "ПометкаУдаления");
	Иначе
		ПоказатьОповещениеПользователя(
			Сценарий.Оповещение,
			Сценарий.Ссылка,
			Сценарий.Пояснение,
			БиблиотекаКартинок.Информация32);
	КонецЕсли;
	ОбщегоНазначенияКлиент.ОповеститьОбИзмененииОбъектов(Сценарий.ВыбранныеЭлементы);
	
КонецПроцедуры

&НаСервере
Функция ИзменитьПометкуУдаленияЭлементов(ВыбранныеЭлементы, Пометка)
	
	Ошибки = Новый Массив;
	Для Каждого Элемент Из ВыбранныеЭлементы Цикл 
		
		НачатьТранзакцию();
		
		Попытка
			
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить(Элемент.Метаданные().ПолноеИмя());
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Элемент);
			Блокировка.Заблокировать();
			
			ВыбранныйОбъект = Элемент.ПолучитьОбъект();
			ЗаблокироватьДанныеДляРедактирования(Элемент);
			ВыбранныйОбъект.УстановитьПометкуУдаления(Пометка);
			
			ЗафиксироватьТранзакцию();
			
		Исключение
			
			ОтменитьТранзакцию();
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Связанные документы.Изменение пометки удаления'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,, Элемент,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			Ошибки.Добавить(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		КонецПопытки;
		
	КонецЦикла;
	
	ОбновитьДеревоСтруктурыПодчиненности();
	Возврат Ошибки;
	
КонецФункции

&НаКлиенте
Процедура ИзменитьПроведениеДокументов(Режим)
	
	ОчиститьСообщения();
	
	ВыбранныеДокументы = ВыбранныеЭлементы();
	Если ВыбранныеДокументы.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Ошибки = Новый Массив;
	ОбработанныеДокументы = ОбработанныеДокументы(ВыбранныеДокументы, Режим, Ошибки);
	КоличествоОбработанныхДокументов = ОбработанныеДокументы.Количество();
	
	Если Ошибки.Количество() > 0 Тогда
		ПредупредитьОбОшибкеПриИзмененииЭлементов(Ошибки, "Проведение");
		Возврат;
	КонецЕсли;
	
	Если КоличествоОбработанныхДокументов = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Если КоличествоОбработанныхДокументов = 1 Тогда 
		Документ = ВыбранныеДокументы[0];
		Оповещение = НСтр("ru = 'Изменение'");
		Ссылка = ПолучитьНавигационнуюСсылку(Документ);
		Пояснение = ОбработанныеДокументы[Документ];
	Иначе
		Ссылка = "";
		Пояснение = Заголовок;
		Оповещение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Изменение (%1)'"), КоличествоОбработанныхДокументов);
	КонецЕсли;
	
	ПоказатьОповещениеПользователя(Оповещение, Ссылка, Пояснение, БиблиотекаКартинок.Информация32);
	ОбщегоНазначенияКлиент.ОповеститьОбИзмененииОбъектов(ВыбранныеДокументы);
	
КонецПроцедуры

&НаСервере
Функция ОбработанныеДокументы(ВыбранныеДокументы, Режим, Ошибки)
	
	ОбработанныеДокументы = Новый Соответствие;
	Индекс = ВыбранныеДокументы.ВГраница();
	Пока Индекс >= 0 Цикл 
		
		МетаданныеОбъекта = ВыбранныеДокументы[Индекс].Метаданные();
		ПроведениеРазрешено = Метаданные.СвойстваОбъектов.Проведение.Разрешить;
		
		Если Не ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта)
			Или МетаданныеОбъекта.Проведение <> ПроведениеРазрешено Тогда 
			
			ВыбранныеДокументы.Удалить(Индекс);
		КонецЕсли;
		
		Индекс = Индекс - 1;
	КонецЦикла;
	
	Если ВыбранныеДокументы.Количество() = 0 Тогда 
		Возврат ОбработанныеДокументы;
	КонецЕсли;
	
	СвойстваДокументов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(ВыбранныеДокументы, "Проведен, Представление");
	Индекс = ВыбранныеДокументы.ВГраница();
	Пока Индекс >= 0 Цикл 
		
		Документ = ВыбранныеДокументы[Индекс];
		СвойстваДокумента = СвойстваДокументов[Документ];
		Если Режим = РежимЗаписиДокумента.ОтменаПроведения И Не СвойстваДокумента.Проведен Тогда 
			ВыбранныеДокументы.Удалить(Индекс);
			Индекс = Индекс - 1;
			Продолжить;
		КонецЕсли;
		Индекс = Индекс - 1;
			
		НачатьТранзакцию();
		Попытка
			
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить(Документ.Метаданные().ПолноеИмя());
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Документ);
			Блокировка.Заблокировать();
			
			ВыбранныйОбъект = Документ.ПолучитьОбъект(); // ДокументОбъект
			Если ВыбранныйОбъект.ПроверитьЗаполнение() Тогда 
				ЗаблокироватьДанныеДляРедактирования(Документ);
				ВыбранныйОбъект.Записать(Режим);
			КонецЕсли;
			
			ОбработанныеДокументы.Вставить(Документ, СвойстваДокумента.Представление);
			ЗафиксироватьТранзакцию();
			
		Исключение
			
			ОтменитьТранзакцию();
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Связанные документы.Проведение документа'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,, Документ,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			Ошибки.Добавить(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		КонецПопытки;
		
	КонецЦикла;
	
	ОбновитьДеревоСтруктурыПодчиненности();
	Возврат ОбработанныеДокументы;
	
КонецФункции

// Общее.

&НаКлиенте
Процедура ПредупредитьОбОшибкеПриИзмененииЭлементов(Ошибки, Сценарий)
	
	ОшибкиСвернутые = ОбщегоНазначенияКлиентСервер.СвернутьМассив(Ошибки);
	Если ОшибкиСвернутые.Количество() = 1 Тогда 
		ТекстПредупреждения = ОшибкиСвернутые[0];
	Иначе
		ШаблонПредупреждения = ?(Сценарий = "ПометкаУдаления", 
			НСтр("ru = 'Не удалось изменить пометку удаления документов:
				|%1'"),
			НСтр("ru = 'Не удалось провести документы:
				|%1'"));
		ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			ШаблонПредупреждения, СтрСоединить(ОшибкиСвернутые, Символы.ПС));
	КонецЕсли;
	
	ПоказатьПредупреждение(, ТекстПредупреждения);
	
КонецПроцедуры

#КонецОбласти
